﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Reflection;
using DevAwesome.WebDataBridge.StorageProviders;
namespace DevAwesome.WebDataBridge {

    public class WebDataBridge : List<Bridge> {

        public Bridge this[ string bridgeName ] {
            get {
                var query = this.Where( x => x.BridgeId == bridgeName.ToLower( ) );
                return HasGroup( bridgeName.ToLower( ) ) ? query.First( ) : null;
            }
            set {
                if( !HasGroup( bridgeName.ToLower( ) ) )
                    this.Add( value );
                else
                    this[ bridgeName.ToLower( ) ] = value;
            }
        }
        private List<IWebDataBridgeStorageProvider> storageProviders;

        private static WebDataBridge _instance = null;
        public static WebDataBridge Instance {
            get {
                if( _instance == null )
                    _instance = new WebDataBridge( );

                return _instance;
            }
            set {
                _instance = value;
            }
        }

        public WebDataBridge( ) {

            if( _instance != null )
                throw new Exception( "BLAH!" );

            if( storageProviders == null )
                storageProviders = new List<IWebDataBridgeStorageProvider>( );

        }

        /// <summary>
        /// Hunt down all the web data bridge registration methods and run them
        /// </summary>
        public static void Initialize( ) {

            Assembly[ ] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies( ).ToArray( );

            //hunt down WebDataBridgeRegistration Methods
            foreach( Assembly assembly in loadedAssemblies )
                foreach( var t in assembly.GetTypes( ) )
                    foreach( var m in t.GetMethods( ) )
                        if( Attribute.IsDefined( m, typeof( WebDataBridgeRegistration ) ) )
                            m.Invoke( Activator.CreateInstance( t ), null );

        }

        #region AddEndPoint

        public WebDataBridge AddEndPoint<T, TProvider>( string bridgeId, string endPoint, string description, Func<T> getDataFunc )
            where T : class
            where TProvider : IWebDataBridgeStorageProvider {


            bool groupExists = this[ bridgeId ] != null;


            if( !groupExists )
                this[ bridgeId ] = new Bridge( bridgeId );


            if( !this[ bridgeId ].HasEndPoint( endPoint ) ) {

                this[ bridgeId ].Add( new EndPoint( this[ bridgeId ], GetStorageProvider<TProvider>( ), getDataFunc ) {
                    EndPointName = endPoint.ToLower( ),
                    Description = description,
                } );

            }

            return this;
        }

        public WebDataBridge AddEndPoint<T>( string bridgeId, string endPoint, string description, Func<T> getDataFunc ) where T : class {
            return AddEndPoint<T, Default>( bridgeId, endPoint, description, getDataFunc );
        }

        public WebDataBridge AddEndPoint<TProvider>( string bridgeId, string endPoint, string description, Func<object> getDataFunc ) where TProvider : IWebDataBridgeStorageProvider {
            return AddEndPoint<object, TProvider>( bridgeId, endPoint, description, getDataFunc );
        }

        #endregion

        public T GetEndPointData<T>( string bridgeId, string endPoint, bool freshData = false ) where T : class {

            var groupExists = this[ bridgeId ] != null;
            var endpointExists = groupExists && this[ bridgeId ][ endPoint ] != null;


            if( endpointExists ) {

                if( freshData )
                    this[ bridgeId ][ endPoint ].Refresh( );

                return this[ bridgeId ][ endPoint ].RetrieveData<T>( );

            }

            return null;

        }

        public object GetEndPointData( string bridgeId, string endPoint, bool freshData = false ) {
            return GetEndPointData<object>( bridgeId, endPoint, freshData );
        }

        private IWebDataBridgeStorageProvider GetStorageProvider<T>( ) where T : IWebDataBridgeStorageProvider {

            if( storageProviders.Where( x => x.GetType( ) == typeof( T ) ).Count( ) == 0 )
                storageProviders.Add( Activator.CreateInstance<T>( ) );

            return storageProviders.Where( x => x.GetType( ) == typeof( T ) ).First( );

        }

        private bool HasGroup( string bridgeId ) {
            var query = this.Where( x => x.BridgeId == bridgeId.ToLower( ) );
            return query.Count( ) == 1;
        }

    }

    [AttributeUsage( System.AttributeTargets.Method )]
    public class WebDataBridgeRegistration : Attribute {
    }

}
